package top.lixunda.ecommerce.server.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.BusinessConstants;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheLoginUser;
import top.lixunda.ecommerce.server.business.api.entity.dto.PageDTO;
import top.lixunda.ecommerce.server.user.api.entity.db.PermissionAllotDO;
import top.lixunda.ecommerce.server.user.api.entity.db.PermissionDO;
import top.lixunda.ecommerce.server.user.api.entity.db.RoleDO;
import top.lixunda.ecommerce.server.user.api.entity.db.SystemMenuDO;
import top.lixunda.ecommerce.server.user.api.entity.dto.PermissionChangeDTO;
import top.lixunda.ecommerce.server.user.api.entity.dto.PermissionInsertDTO;
import top.lixunda.ecommerce.server.user.api.entity.dto.PermissionQueryDTO;
import top.lixunda.ecommerce.server.user.mapper.PermissionMapper;
import top.lixunda.ecommerce.server.user.service.IPermissionAllotService;
import top.lixunda.ecommerce.server.user.service.IPermissionService;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 权限表，权限的最小原子单位 服务实现类
 * </p>
 *
 * @author Lixunda
 * @since 2020-04-24
 */
@Service
public class PermissionServiceImpl extends BaseServiceImpl<PermissionMapper, PermissionDO>
        implements IPermissionService {

    private final IPermissionAllotService permissionAllotService;

    @Autowired
    public PermissionServiceImpl(IPermissionAllotService permissionAllotService) {
        this.permissionAllotService = permissionAllotService;
    }

    /**
     * 插入角色权限，内部调用，当新建角色时自动插入角色自带的角色权限
     *
     * @param roleList 插入成功后的角色数据
     * @return 权限信息
     */
    @Override
    public List<PermissionDO> insertAutoRolePermission(List<RoleDO> roleList) {
        if (ObjectValidators.isEmpty(roleList)) {
            throw getAppException("添加角色权限失败！参数不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        // 添加权限信息
        List<PermissionDO> insert = roleList.stream()
                .map(item -> new PermissionDO().setCreateMode(BusinessConstants.PERMISSION_CREATE_MODE_SELF)
                        .setPermissionCode("ROLE-" + item.getRoleId())
                        .setPermissionName("角色权限:" + item.getRoleName())
                        .setPermissionDesc("角色自带权限，自动添加！")
                        .setCreateTime(localDateTime)
                        .setCreateUserId(cacheLoginUser.getAccount())
                        .setCreateUserName(cacheLoginUser.getName())
                        .setCreateUserType(cacheLoginUser.getType()))
                .collect(Collectors.toList());
        this.saveBatch(insert);
        // 分配权限
        List<PermissionAllotDO> allotInsert = insert.stream()
                .map(item -> {
                    PermissionAllotDO permissionAllotDO = new PermissionAllotDO();
                    String strRoleId = item.getPermissionCode().split("-")[1];
                    Integer roleId = Integer.parseInt(strRoleId);
                    permissionAllotDO.setAllotMode(BusinessConstants.ALLOT_MODE_SELF)
                            .setPermissionId(item.getPermissionId())
                            .setAllotPart(BusinessConstants.PERMISSION_ALLOT_PART_ROLE)
                            .setPartId(roleId)
                            .setCreateTime(localDateTime)
                            .setCreateUserId(cacheLoginUser.getAccount())
                            .setCreateUserName(cacheLoginUser.getName())
                            .setCreateUserType(cacheLoginUser.getType());
                    return permissionAllotDO;
                })
                .collect(Collectors.toList());
        permissionAllotService.saveBatch(allotInsert);
        return insert;
    }

    /**
     * 插入菜单权限，内部调用，当新建菜单时自动插入菜单自带的菜单权限
     *
     * @param systemMenuList 插入成功后的菜单数据
     * @return 权限信息
     */
    @Override
    public List<PermissionDO> insertAutoMenuPermission(List<SystemMenuDO> systemMenuList) {
        if (ObjectValidators.isEmpty(systemMenuList)) {
            throw getAppException("添加菜单权限失败！参数不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        // 添加普通权限信息
        List<PermissionDO> insert = systemMenuList.stream()
                .flatMap(item -> Stream.of(
                        new PermissionDO()
                                .setCreateMode(BusinessConstants.PERMISSION_CREATE_MODE_SELF)
                                .setPermissionCode("MENU-" + item.getMenuCode() + "-" + item.getMenuId())
                                .setPermissionName("菜单权限:" + item.getMenuName())
                                .setPermissionDesc("菜单自带权限，自动添加！")
                                .setCreateTime(localDateTime)
                                .setCreateUserId(cacheLoginUser.getAccount())
                                .setCreateUserName(cacheLoginUser.getName())
                                .setCreateUserType(cacheLoginUser.getType()),
                        new PermissionDO()
                                .setCreateMode(BusinessConstants.PERMISSION_CREATE_MODE_SELF)
                                .setPermissionCode("MENU-READ-" + item.getMenuCode() + "-" + item.getMenuId())
                                .setPermissionName("菜单权限:" + item.getMenuName())
                                .setPermissionDesc("菜单自带权限，自动添加！")
                                .setCreateTime(localDateTime)
                                .setCreateUserId(cacheLoginUser.getAccount())
                                .setCreateUserName(cacheLoginUser.getName())
                                .setCreateUserType(cacheLoginUser.getType()),
                        new PermissionDO()
                                .setCreateMode(BusinessConstants.PERMISSION_CREATE_MODE_SELF)
                                .setPermissionCode("MENU-UPDATE-" + item.getMenuCode() + "-" + item.getMenuId())
                                .setPermissionName("菜单权限:" + item.getMenuName())
                                .setPermissionDesc("菜单自带权限，自动添加！")
                                .setCreateTime(localDateTime)
                                .setCreateUserId(cacheLoginUser.getAccount())
                                .setCreateUserName(cacheLoginUser.getName())
                                .setCreateUserType(cacheLoginUser.getType())))
                .collect(Collectors.toList());
        this.saveBatch(insert);
        // 分配权限
        List<PermissionAllotDO> allotInsert = insert.stream()
                .map(item -> {
                    PermissionAllotDO permissionAllotDO = new PermissionAllotDO();
                    String[] strMenuIds = item.getPermissionCode().split("-");
                    String strMenuId = strMenuIds[strMenuIds.length - 1];
                    Integer menuId = Integer.parseInt(strMenuId);
                    permissionAllotDO.setAllotMode(BusinessConstants.ALLOT_MODE_SELF)
                            .setPermissionId(item.getPermissionId())
                            .setAllotPart(BusinessConstants.PERMISSION_ALLOT_PART_MENU)
                            .setPartId(menuId)
                            .setCreateTime(localDateTime)
                            .setCreateUserId(cacheLoginUser.getAccount())
                            .setCreateUserName(cacheLoginUser.getName())
                            .setCreateUserType(cacheLoginUser.getType());
                    return permissionAllotDO;
                })
                .collect(Collectors.toList());
        permissionAllotService.saveBatch(allotInsert);
        return insert;
    }

    /**
     * 移除角色权限，内部调用，当移除角色时自动移除角色自带的角色权限
     *
     * @param ids 角色编号列表
     * @return 是否移除成功
     */
    @Override
    public Boolean removeAutoRolePermission(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("删除角色权限失败！角色编号列表不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        // 查询角色分配的权限
        List<PermissionAllotDO> allotList = permissionAllotService.list(
                new LambdaQueryWrapper<PermissionAllotDO>()
                        .select(PermissionAllotDO::getAllotId, PermissionAllotDO::getPermissionId)
                        .eq(PermissionAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_SELF)
                        .eq(PermissionAllotDO::getAllotPart, BusinessConstants.PERMISSION_ALLOT_PART_ROLE)
                        .in(PermissionAllotDO::getPartId, ids));
        if (ObjectValidators.isEmpty(allotList)) {
            throw getAppException("删除角色权限失败！角色分配列表为空！");
        }
        // 获取ID列表
        List<Integer> allotIdList = allotList.stream()
                .map(PermissionAllotDO::getAllotId)
                .collect(Collectors.toList());
        List<Integer> permissionIdList = allotList.stream()
                .map(PermissionAllotDO::getPermissionId)
                .collect(Collectors.toList());
        // 移除权限分配数据
        boolean success = permissionAllotService.update(
                new LambdaUpdateWrapper<PermissionAllotDO>()
                        .set(PermissionAllotDO::getUsable, BusinessConstants.USEABLE_FALSE)
                        .set(PermissionAllotDO::getRemoveTime, localDateTime)
                        .set(PermissionAllotDO::getRemoveUserId, cacheLoginUser.getAccount())
                        .set(PermissionAllotDO::getRemoveUserName, cacheLoginUser.getName())
                        .set(PermissionAllotDO::getRemoveUserType, cacheLoginUser.getType())
                        .in(PermissionAllotDO::getAllotId, allotIdList)
                        .eq(PermissionAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_HAND));
        if (!success) {
            throw getAppException("删除角色权限分配信息失败！修改数据失败！");
        }
        // 移除权限数据
        success = this.update(new LambdaUpdateWrapper<PermissionDO>()
                .set(PermissionDO::getUsable, BusinessConstants.USEABLE_FALSE)
                .set(PermissionDO::getRemoveTime, localDateTime)
                .set(PermissionDO::getRemoveUesrId, cacheLoginUser.getAccount())
                .set(PermissionDO::getRemoveUserName, cacheLoginUser.getName())
                .set(PermissionDO::getRemoveUserType, cacheLoginUser.getType())
                .in(PermissionDO::getPermissionId, permissionIdList)
                .eq(PermissionDO::getCreateMode, BusinessConstants.PERMISSION_CREATE_MODE_HAND));
        if (!success) {
            throw getAppException("删除角色权限失败！修改数据失败！");
        }
        return true;
    }

    /**
     * 移除菜单权限，内部调用，当移除菜单时自动移除菜单自带的菜单权限
     *
     * @param ids 菜单编号列表
     * @return 权限信息
     */
    @Override
    public Boolean removeAutoMenuPermission(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("删除菜单权限失败！菜单编号列表不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        // 查询菜单分配的权限
        List<PermissionAllotDO> allotList = permissionAllotService.list(
                new LambdaQueryWrapper<PermissionAllotDO>()
                        .select(PermissionAllotDO::getAllotId, PermissionAllotDO::getPermissionId)
                        .eq(PermissionAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_SELF)
                        .eq(PermissionAllotDO::getAllotPart, BusinessConstants.PERMISSION_ALLOT_PART_MENU)
                        .in(PermissionAllotDO::getPartId, ids));
        if (ObjectValidators.isEmpty(allotList)) {
            throw getAppException("删除菜单权限失败！菜单分配列表为空！");
        }
        // 获取ID列表
        List<Integer> allotIdList = allotList.stream()
                .map(PermissionAllotDO::getAllotId)
                .collect(Collectors.toList());
        List<Integer> permissionIdList = allotList.stream()
                .map(PermissionAllotDO::getPermissionId)
                .collect(Collectors.toList());
        // 移除权限分配数据
        boolean success = permissionAllotService.update(
                new LambdaUpdateWrapper<PermissionAllotDO>()
                        .set(PermissionAllotDO::getUsable, BusinessConstants.USEABLE_FALSE)
                        .set(PermissionAllotDO::getRemoveTime, localDateTime)
                        .set(PermissionAllotDO::getRemoveUserId, cacheLoginUser.getAccount())
                        .set(PermissionAllotDO::getRemoveUserName, cacheLoginUser.getName())
                        .set(PermissionAllotDO::getRemoveUserType, cacheLoginUser.getType())
                        .in(PermissionAllotDO::getAllotId, allotIdList)
                        .eq(PermissionAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_HAND));
        if (!success) {
            throw getAppException("删除菜单权限分配信息失败！修改数据失败！");
        }
        // 移除权限数据
        success = this.update(new LambdaUpdateWrapper<PermissionDO>()
                .set(PermissionDO::getUsable, BusinessConstants.USEABLE_FALSE)
                .set(PermissionDO::getRemoveTime, localDateTime)
                .set(PermissionDO::getRemoveUesrId, cacheLoginUser.getAccount())
                .set(PermissionDO::getRemoveUserName, cacheLoginUser.getName())
                .set(PermissionDO::getRemoveUserType, cacheLoginUser.getType())
                .in(PermissionDO::getPermissionId, permissionIdList)
                .eq(PermissionDO::getCreateMode, BusinessConstants.PERMISSION_CREATE_MODE_HAND));
        if (!success) {
            throw getAppException("删除菜单权限失败！修改数据失败！");
        }
        return true;
    }

    /**
     * 添加单独的权限，超级管理员调用
     *
     * @param insertList 权限添加数据DTO
     * @return 添加成功的权限信息
     */
    @Override
    public List<PermissionDO> insertPermission(List<PermissionInsertDTO> insertList) {
        if (ObjectValidators.isEmpty(insertList)) {
            throw getAppException("添加普通权限失败！参数不能为空！");
        }
        // 检验参数，编号不能以 MENU- 和 ROLE- 开头
        insertList.forEach(item -> {
            if (ObjectValidators.isEmpty(item.getPermissionCode())
                    || item.getPermissionCode().startsWith("MENU-")
                    || item.getPermissionCode().startsWith("ROLE-")) {
                throw getAppException("添加普通权限失败！不合法的权限编码：" + item.getPermissionCode());
            }
        });
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        // 添加权限信息
        List<PermissionDO> insert = insertList.stream()
                .map(item -> new PermissionDO().setCreateMode(BusinessConstants.PERMISSION_CREATE_MODE_HAND)
                        .setPermissionCode(item.getPermissionCode())
                        .setPermissionName(item.getPermissionName())
                        .setPermissionDesc(item.getPermissionDesc())
                        .setCreateTime(localDateTime)
                        .setCreateUserId(cacheLoginUser.getAccount())
                        .setCreateUserName(cacheLoginUser.getName())
                        .setCreateUserType(cacheLoginUser.getType()))
                .collect(Collectors.toList());
        this.saveBatch(insert);
        return insert;
    }

    /**
     * 根据权限编号修改权限信息，超级管理员调用，只能修改创建的权限
     *
     * @param changeList 权限修改数据DTO
     * @return 修改后的权限信息
     */
    @Override
    public List<PermissionDO> changePermissionById(List<PermissionChangeDTO> changeList) {
        if (ObjectValidators.isEmpty(changeList)) {
            throw getAppException("修改普通权限失败！参数不能为空！");
        }
        // 检验参数，编号不能以 MENU- 和 ROLE- 开头
        changeList.forEach(item -> {
            if (ObjectValidators.isEmpty(item.getPermissionCode())
                    || item.getPermissionCode().startsWith("MENU-")
                    || item.getPermissionCode().startsWith("ROLE-")) {
                throw getAppException("修改普通权限失败！不合法的权限编码：" + item.getPermissionCode());
            }
        });
        // 添加权限信息
        List<PermissionDO> update = changeList.stream()
                .map(item -> new PermissionDO()
                        .setPermissionId(item.getPermissionId())
                        .setPermissionCode(item.getPermissionCode())
                        .setPermissionName(item.getPermissionName())
                        .setPermissionDesc(item.getPermissionDesc()))
                .collect(Collectors.toList());
        update.forEach(item -> {
            boolean success = this.update(item, new LambdaUpdateWrapper<PermissionDO>()
                    .eq(PermissionDO::getPermissionId, item.getPermissionId())
                    .eq(PermissionDO::getCreateMode, BusinessConstants.PERMISSION_CREATE_MODE_HAND));
            if (!success) {
                throw getAppException("修改普通权限失败！权限不存在或该权限不能修改！");
            }
        });
        return update;
    }

    /**
     * 根据权限编号删除权限信息，超级管理员调用，只能移除创建的权限
     *
     * @param permissionIdList 权限编号列表
     * @return 删除的权限信息列表
     */
    @Override
    public Boolean removePermission(List<Integer> permissionIdList) {
        if (ObjectValidators.isEmpty(permissionIdList)) {
            throw getAppException("删除普通权限失败！权限编号列表不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        // 移除权限分配数据
        boolean success = permissionAllotService.update(
                new LambdaUpdateWrapper<PermissionAllotDO>()
                        .set(PermissionAllotDO::getUsable, BusinessConstants.USEABLE_FALSE)
                        .set(PermissionAllotDO::getRemoveTime, localDateTime)
                        .set(PermissionAllotDO::getRemoveUserId, cacheLoginUser.getAccount())
                        .set(PermissionAllotDO::getRemoveUserName, cacheLoginUser.getName())
                        .set(PermissionAllotDO::getRemoveUserType, cacheLoginUser.getType())
                        .in(PermissionAllotDO::getPermissionId, permissionIdList)
                        .eq(PermissionAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_HAND));
        if (!success) {
            throw getAppException("删除普通权限分配信息失败！修改数据失败！");
        }
        // 移除权限数据
        success = this.update(new LambdaUpdateWrapper<PermissionDO>()
                .set(PermissionDO::getUsable, BusinessConstants.USEABLE_FALSE)
                .set(PermissionDO::getRemoveTime, localDateTime)
                .set(PermissionDO::getRemoveUesrId, cacheLoginUser.getAccount())
                .set(PermissionDO::getRemoveUserName, cacheLoginUser.getName())
                .set(PermissionDO::getRemoveUserType, cacheLoginUser.getType())
                .in(PermissionDO::getPermissionId, permissionIdList)
                .eq(PermissionDO::getCreateMode, BusinessConstants.PERMISSION_CREATE_MODE_HAND));
        if (!success) {
            throw getAppException("删除普通权限失败！修改数据失败！");
        }
        return true;
    }

    /**
     * 根据权限编号查询单个权限信息，超级管理员调用
     *
     * @param id 权限编号
     * @return 单个权限信息
     */
    @Override
    public PermissionDO queryPermissionById(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("查询权限数据失败！权限编号不能为空！");
        }
        return this.getById(id);
    }

    /**
     * 根据多个权限编号查询多个权限信息，超级管理员调用
     *
     * @param ids 权限编号列表
     * @return 权限信息列表
     */
    @Override
    public List<PermissionDO> queryPermissionByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("查询权限数据失败！权限编号列表不能为空！");
        }
        return (List<PermissionDO>) this.listByIds(ids);
    }

    /**
     * 条件分页查询权限数据，超级管理员调用
     *
     * @param pageDTO 分页条件DTO
     * @return 分页数据
     */
    @Override
    public IPage<PermissionDO> queryPermissionPageWrapper(PageDTO<PermissionDO, PermissionQueryDTO> pageDTO) {
        if (ObjectValidators.isEmpty(pageDTO)) {
            throw getAppException("查询权限数据失败！参数不能为空！");
        }
        return this.page(pageDTO.getPage(), pageDTO.getWrapper(
                wrapper -> wrapper.orderByDesc(PermissionDO::getPermissionName)));
    }
}
